package club_service

import (
	"errors"
	"fmt"
	"gorm.io/gorm"
	"shimmer/neusoft_club_backend/controllers/utils"
	"shimmer/neusoft_club_backend/dao/domain"
	"shimmer/neusoft_club_backend/services"
	"shimmer/neusoft_club_backend/services/errs"
	"time"
)

func GetUsersUserStruct(userID int64, query *utils.PaginationQuery) (res utils.Pagination, err error) {
	p := make([]*domain.ClubUserStruct, 0)
	res, err = utils.QueryAndPaginate(query, services.DBEngine.Where("user_id = ?", userID).Joins(domain.ClubUserStructFieldPosition), &p)

	if err != nil {
		return
	}
	return
}

type CreateClubReq struct {
	Name         string  `json:"name" xml:"name" form:"name" binding:"required"`
	FaviconID    *int64  `json:"favicon_id" xml:"favicon_id" form:"favicon_id"`
	PageID       *int64  `json:"page_id" xml:"page_id" form:"page_id"`
	Introduction *string `json:"introduction" xml:"introduction" form:"introduction"`
	Location     *string `json:"location" xml:"location" form:"location"`
	Address      *string `json:"address" xml:"address" form:"address"`
	PrimaryColor string  `json:"primary_color" xml:"primary_color" form:"primary_color"`
}

func CreateClub(req CreateClubReq) (res *domain.Club, err error) {
	res = &domain.Club{
		Name:         req.Name,
		FaviconID:    req.FaviconID,
		PageID:       req.PageID,
		Introduction: req.Introduction,
		Location:     req.Location,
		Address:      req.Address,
		PrimaryColor: req.PrimaryColor,
	}
	if err = services.DBEngine.Save(res).Error; err != nil {
		return
	}
	return
}

// GetUsersDepartments
//  获取用户的所有职位
func GetUsersDepartments(userID int64, query *utils.PaginationQuery) (res utils.Pagination, err error) {
	d := make([]*domain.ClubDepartmentStruct, 0)
	res, err = utils.QueryAndPaginate(query, services.DBEngine.Where("id in (?)", services.DBEngine.Model(&domain.Club{}).Where("id in (?)", services.DBEngine.Model(&domain.UserActor{}).Where("user_id = ? and club_id is not null", userID).Select("club_id")).Select("id")), &d)
	return
}
func GetClubsWithUserJoined(userID int64, query *utils.PaginationQuery) (res utils.Pagination, err error) {
	c := make([]*domain.Club, 0)

	res, err = utils.QueryAndPaginate(query, services.DBEngine.Where("id in (?)", services.DBEngine.Model(&domain.UserActor{}).Where("user_id=? and club_id is not null", userID).Select("club_id")), &c)
	return
}

func GetClubPageByClubID(clubID int64) (res *domain.ClubPage, err error) {
	club := &domain.Club{ID: clubID}
	if err = services.DBEngine.Joins(domain.ClubFieldPage).First(club).Error; err != nil {
		return
	}
	return club.Page, nil
}

type UpsertClubPageReq struct {
	Title       string                 `json:"title"`
	Content     map[string]interface{} `json:"content"`
	ContentText string                 `json:"content_text"`
}

func UpsertClubPageByClubID(clubID int64, req *UpsertClubPageReq) (res *domain.ClubPage, err error) {
	club := &domain.Club{ID: clubID}
	if err = services.DBEngine.Joins(domain.ClubFieldPage).First(club).Error; err != nil {
		return
	}
	isNew := false
	page := club.Page
	if page == nil {
		page = &domain.ClubPage{}
		isNew = true
	}
	content := domain.NewJSON(req.Content)
	page.Title = req.Title
	page.Content = &content
	page.ContentText = &req.ContentText
	if err = services.DBEngine.Save(page).Error; err != nil {
		return
	}
	if isNew {
		club.PageID = &page.ID
		if err = services.DBEngine.Save(club).Error; err != nil {
			return
		}
	}
	res = page
	return
}
func GetAllClubs(where map[string]interface{}, query *utils.PaginationQuery) (res utils.Pagination, err error) {
	c := make([]*domain.Club, 0)
	db := services.DBEngine.Joins(domain.ClubFieldPage).Joins(domain.ClubFieldFavicon).Preload(domain.ClubFieldLeaders).Preload(domain.ClubFieldCoverImages).Preload(fmt.Sprintf("%s.%s", domain.ClubFieldLeaders, domain.UserActorFieldUser))
	db = services.BuildWhere(where, db)
	db.Find(&c)
	res, err = utils.QueryAndPaginate(query, db, &c)
	if err != nil {
		return
	}
	return
}

func CheckIsClubOwner(userID, clubID int64) (res bool, err error) {
	actors := make([]*domain.UserActor, 0)
	err = services.DBEngine.Where("user_id=? and (club_id =? or club_id is null)", userID, clubID).Find(&actors).Error
	role := domain.AuthorizationRole(0)
	for _, actor := range actors {
		role = role.Add(actor.Role)
	}
	res = role.Has(domain.AuthLeader) || role.Has(domain.AuthAdmin)
	return
}

func CheckIsClubApplicant(userID, clubID int64) (res bool, err error) {
	var count int64 = 0
	subQuery1 := services.DBEngine.Model(&domain.ClubForm{}).Where("club_id = ?", clubID).Select("id")
	subQuery2 := services.DBEngine.Model(&domain.UserApplication{}).Select("user_id").Where("form_id in (?)", subQuery1)
	err = services.DBEngine.Model(&domain.User{ID: userID}).Where("id in (?)", subQuery2).Count(&count).Error
	if err != nil {
		return
	}
	return count > 0, nil
}

func CheckInClub(userID, clubID int64) (res bool, err error) {
	actors := make([]*domain.UserActor, 0)
	err = services.DBEngine.Where("user_id=? and (club_id =? or club_id is null)", userID, clubID).Find(&actors).Error
	role := domain.AuthorizationRole(0)
	for _, actor := range actors {
		role = role.Add(actor.Role)
	}
	res = role.Has(domain.AuthStudent) || role.Has(domain.AuthLeader) || role.Has(domain.AuthAdmin)
	return
}

func CheckIsAdmin(userID int64) (res bool, err error) {
	actors := make([]*domain.UserActor, 0)
	err = services.DBEngine.Where("user_id=? and club_id is null", userID).Find(&actors).Error

	if err != nil {
		return
	}
	role := domain.AuthorizationRole(0)
	for _, actor := range actors {
		role = role.Add(actor.Role)
	}
	res = role.Has(domain.AuthAdmin)
	return
}

func ExitClub(userID int64, clubID int64) (err error) {
	err = services.DBEngine.Transaction(func(db *gorm.DB) (err error) {
		// 删除部门成员
		err = db.Where("user_id=? and club_id=?", userID, clubID).Delete(&domain.ClubDepartmentStruct{}).Error
		if err != nil {
			return
		}
		// 删除社团成员
		err = db.Where("user_id = ? and club_id =?", userID, clubID).Delete(&domain.ClubUserStruct{}).Error
		if err != nil {
			return
		}
		// 删除社团角色
		err = db.Where("user_id = ? and club_id =?", userID, clubID).Delete(&domain.UserActor{}).Error
		if err != nil {
			return
		}
		return
	})
	shouldHidden, _ := CheckClubShouldBeHidden(clubID)
	if shouldHidden {
		err = services.DBEngine.Model(&domain.Club{ID: clubID}).Update(domain.ClubColumnOuterVisible, false).Error
	}
	return
}
func GetAllClubForms(clubID int64, query *utils.PaginationQuery) (res utils.Pagination, err error) {
	forms := make([]*domain.ClubForm, 0)
	res, err = utils.QueryAndPaginate(query, services.DBEngine.Where("club_id=?", clubID), &forms)
	return
}

func GetJoinClubForm(clubID int64) (res *domain.ClubForm, err error) {
	res = &domain.ClubForm{}
	err = services.DBEngine.Find(res).Where("club_id=? and type=0", clubID).Error
	return
}

func CheckClubShouldBeHidden(clubID int64) (res bool, err error) {
	club := &domain.Club{ID: clubID}
	err = services.DBEngine.Preload(domain.ClubFieldLeaders).Find(club).Error
	res = len(club.Leaders) == 0
	return
}

func FindUsersApplicationByID(id int64) (res *domain.UserApplication, err error) {
	res = &domain.UserApplication{}
	err = services.DBEngine.Joins(domain.UserApplicationFieldStatus).Preload(domain.UserApplicationFieldForm).Where("user_applications.id=?", id).First(res).Error
	return
}

func FindUsersApplicationAndAuth(applicationID, userID int64) (res *domain.UserApplication, err error) {
	res, err = FindUsersApplicationByID(applicationID)
	if err != nil {
		return
	}
	if res.UserID != userID {
		// 查看其他人的申请
		if res.Form != nil && res.Form.ClubID != nil {
			owner, err := CheckIsClubOwner(userID, *res.Form.ClubID)
			if err != nil {
				return nil, err
			}
			if !owner {
				// 非拥有者无权查看
				return nil, errs.ErrApplicationViewForbidden
			}
		}
	}
	return
}

//
//func FindUsersApplicationForClub(userID,clubID int64,query *utils.PaginationQuery) (res utils.Pagination,err error) {
//	applications := make([]*domain.UserApplication,0)
//	res,err = utils.QueryAndPaginate(query,services.DBEngine.Find(applications).Where("user_id = ? and club_id =?",userID,clubID).Joins(domain.UserApplicationFieldStatus),&applications)
//	return
//}

func FindUsersApplicationStatusByID(id int64) (res *domain.ClubFormStatusFlow, err error) {
	application := &domain.UserApplication{ID: id}
	err = services.DBEngine.Find(application).Joins(domain.UserApplicationFieldStatus).Error
	if err != nil {
		return
	}
	res = application.Status
	return
}
func FindAllUsersApplication(userID int64, query *utils.PaginationQuery) (res utils.Pagination, err error) {
	applications := make([]*domain.UserApplication, 0)
	res, err = utils.QueryAndPaginate(query, services.DBEngine.Where("user_id = ?", userID).Joins(domain.UserApplicationFieldForm).Joins(domain.UserApplicationFieldStatus), &applications)
	return
}
func FindAllApplicationForClub(clubID int64, query *utils.PaginationQuery) (res utils.Pagination, err error) {
	applications := make([]*domain.UserApplication, 0)
	res, err = utils.QueryAndPaginate(query, services.DBEngine.Joins(domain.UserApplicationFieldForm).Joins(domain.UserApplicationFieldStatus).Where(
		fmt.Sprintf("%s.form_id in (?) and %s.type != %d", domain.UserApplicationTableName, domain.UserApplicationFieldStatus, domain.ClubFormStatusFlowTypeDraft), services.DBEngine.Model(&domain.ClubForm{}).Where("club_id = ?", clubID).Select("id")), &applications)
	return
}

func FindAllApplicationFromClubByStatus(clubID, statusID int64, query *utils.PaginationQuery) (res utils.Pagination, err error) {
	applications := make([]*domain.UserApplication, 0)
	db := services.DBEngine.Joins(domain.UserApplicationFieldForm).Joins(domain.UserApplicationFieldStatus).Where(fmt.Sprintf("%s.form_id in (?)", domain.UserApplicationTableName), services.DBEngine.Model(&domain.ClubForm{}).Where("club_id = ?", clubID).Select("id"))
	if statusID != 0 {
		db = db.Where(fmt.Sprintf("%s.id = ? and %s.type != %d", domain.UserApplicationFieldStatus, domain.UserApplicationFieldStatus, domain.ClubFormStatusFlowTypeDraft), statusID)
	}
	res, err = utils.QueryAndPaginate(query, db, &applications)
	return
}

type EndOfApplicationMutation struct {
	DisallowPostDuration *time.Duration `json:"disallow_post_duration" form:"disallow_post_duration" xml:"disallow_post_duration" binding:"-"`
}
type EndOfApplicationMutationDTO struct {
	DisallowPostDuration *int64 `json:"disallow_post_duration" form:"disallow_post_duration" xml:"disallow_post_duration" binding:"-"`
}
type AcceptApplicationMutation struct {
	EndOfApplicationMutation
}
type AcceptApplicationMutationDTO struct {
	EndOfApplicationMutationDTO
}
type RejectApplicationMutation struct {
	EndOfApplicationMutation
}
type RejectApplicationMutationDTO struct {
	EndOfApplicationMutationDTO
}

func FindDefaultFailureStatusByClubID(clubID int64) (res *domain.ClubFormStatusFlow, err error) {
	res = &domain.ClubFormStatusFlow{}
	err = services.DBEngine.Where("club_id = ? and is_default_failure = true", clubID).First(res).Error
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			err = errs.ErrFormStatusFailureNotSet
		}
	}
	return
}
func FindStatus(where map[string]interface{}) (res *domain.ClubFormStatusFlow, err error) {
	res = &domain.ClubFormStatusFlow{}
	db := services.DBEngine
	db = services.BuildWhere(where, db)
	err = db.First(res).Error
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			err = errs.ErrFormStatusSuccessNotSet
		}
	}
	return
}

func FindDraftFormStatus() (res *domain.ClubFormStatusFlow, err error) {
	res = &domain.ClubFormStatusFlow{}
	if err = services.DBEngine.Where("type=?", domain.ClubFormStatusFlowTypeDraft).First(res).Error; err != nil {
		return
	}
	return
}

func AcceptApplication(applicationID, formID, clubID int64, mutation *AcceptApplicationMutation) (err error) {
	res, err := FindStatus(map[string]interface{}{
		"club_id":            clubID,
		"form_id":            formID,
		"is_default_success": true,
	})
	if err != nil {
		return
	}
	err = services.DBEngine.Transaction(func(tx *gorm.DB) (err error) {
		err = UpdateApplicationStatusFlowWithTransaction(applicationID, res.ID, tx)
		if err != nil {
			return
		}
		if mutation.DisallowPostDuration != nil {
			tx.Model(&domain.UserApplication{ID: applicationID}).Update(domain.UserApplicationColumnNextUpdateTime, time.Now().Add(*mutation.DisallowPostDuration))
		}
		return
	})
	return
}

func RejectApplication(applicationID, formId, clubID int64, mutation *RejectApplicationMutation) (err error) {
	res, err := FindStatus(map[string]interface{}{
		"club_id":            clubID,
		"form_id":            formId,
		"is_default_failure": true,
	})
	if err != nil {
		return
	}
	err = services.DBEngine.Transaction(func(tx *gorm.DB) (err error) {
		// 设置为拒绝状态
		err = UpdateApplicationStatusFlowWithTransaction(applicationID, res.ID, tx)
		if err != nil {
			return

		}
		// 如果设置了禁止提交持续时间，则更新时间
		if mutation.DisallowPostDuration != nil {
			tx.Model(&domain.UserApplication{ID: applicationID}).Update(domain.UserApplicationColumnNextUpdateTime, time.Now().Add(*mutation.DisallowPostDuration))
		}
		return
	})
	return

}
func UpdateApplicationStatusFlowWithTransaction(applicationID, statusFlowID int64, db *gorm.DB) (err error) {
	if err = db.Model(&domain.UserApplication{ID: applicationID}).Update("status_id", statusFlowID).Error; err != nil {
		return
	}
	return
}
func UpdateApplicationStatusFlow(applicationID, statusFlowID int64) (err error) {

	err = UpdateApplicationStatusFlowWithTransaction(applicationID, statusFlowID, services.DBEngine)
	return
}
func FindClubFormStatusFlow(flowID int64) (res *domain.ClubFormStatusFlow, err error) {
	res = &domain.ClubFormStatusFlow{ID: flowID}
	if err = services.DBEngine.First(res).Error; err != nil {
		return
	}
	return
}

func PublishApplication(application *domain.UserApplication) (status *domain.ClubFormStatusFlow, err error) {
	status = &domain.ClubFormStatusFlow{}
	if err = services.DBEngine.Where("form_id = ? and parent_id is null", *application.FormID).First(status).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			err = errs.ErrDefaultStatusIsNotSet
			return
		}
		return
	}
	if err = services.DBEngine.Model(&domain.UserApplication{ID: application.ID}).Update("status_id", status.ID).Error; err != nil {
		return
	}
	return
}

func CancelApplication(application *domain.UserApplication) (err error) {
	if err = services.DBEngine.Where("id=?", application.ID).Delete(&domain.UserApplication{}).Error; err != nil {
		return
	}
	return
}

func GetUserRolesForClubWithTransaction(userID int64, clubID int64, db *gorm.DB) (role domain.AuthorizationRole, err error) {
	actors := make([]*domain.UserActor, 0)
	err = db.Find(&actors).Where("user_id=? and (club_id=? or club_id is null)", userID, clubID).Error
	for _, userActor := range actors {
		userRole := userActor.Role
		if userActor.ClubID == nil {
			if userRole.Has(domain.AuthAdmin) {
				role.Add(userRole)
			}
			continue
		}
		role.Add(userRole)
	}
	return
}
func InviteUserJoinClubWithTransaction(mutation *InviteUserJoinClubMutation, db *gorm.DB) (err error) {
	userID, clubID, operatorID := mutation.UserID, mutation.ClubID, mutation.OperatorID
	// 判断用户是否为社团成员
	role, err := GetUserRolesForClubWithTransaction(userID, clubID, db)
	if err != nil {
		return
	}
	// 已经是成员，or 已经是社长 or 已经是管理员
	if role > 0 {
		return errs.ErrClubMemberAlreadyExists
	}

	role, err = GetUserRolesForClubWithTransaction(operatorID, clubID, db)

	// 判断用户是否提交过申请表单

	// 找到申请表单
	applicationForm := &domain.ClubForm{}
	err = db.Find(applicationForm).Where("club_id = ? and type = 0", clubID).Error
	if err != nil {
		return
	}
	// 找到申请
	application := &domain.UserApplication{}
	err = db.Find(application).Where("user_id = ? and form_id = ?", userID, applicationForm.ID).Error
	if err != nil {
		if !errors.Is(err, gorm.ErrRecordNotFound) {
			return
		}
		// 没有找到
		if !role.Has(domain.AuthAdmin) {
			return
		}
		// 是管理员则继续
	}

	// 首先增加用户角色
	userActor := &domain.UserActor{
		UserID: userID,
		Role:   domain.AuthStudent,
	}

	db.Save(userActor)

	// 然后查找默认部门和默认职位并尝试插入

	defaultDepartment := &domain.ClubDepartmentStruct{}

	err = db.Find(defaultDepartment).Where("club_id = ? and is_default_join = true").Error
	isExist := true
	if err != nil {
		if !errors.Is(err, gorm.ErrRecordNotFound) {
			return
		}
		err = nil
		isExist = false
	}

	if isExist {
		err = db.Model(defaultDepartment).Association(domain.ClubDepartmentFieldMembers).Append(&domain.User{ID: userID})
		if err != nil {
			return
		}
	}

	defaultPosition := &domain.ClubPosition{}
	err = db.Find(defaultPosition).Where("club_id = ? and is_default_join = true").Error
	isExist = true
	if err != nil {
		if !errors.Is(err, gorm.ErrRecordNotFound) {
			return
		}
		err = nil
		isExist = false
	}
	// 直接新建用户结构
	userStruct := &domain.ClubUserStruct{
		UserID: userID,
		ClubID: &clubID,
	}
	if isExist {
		userStruct.PositionID = &defaultPosition.ID
	}
	db.Save(userStruct)

	return
}
func AddLeaderToClub(user *domain.User, clubID int64) (err error) {
	return addLeaderToClub(user, clubID, services.DBEngine)
}
func addLeaderToClub(user *domain.User, clubID int64, db *gorm.DB) (err error) {
	err = db.Model(&domain.Club{ID: clubID}).Association(domain.ClubFieldLeaders).Append(user)
	return
}

func RemoveLeaderFromClub(user *domain.User, clubID int64) (err error) {
	return removeLeaderFromClub(user, clubID, services.DBEngine)
}
func removeLeaderFromClub(user *domain.User, clubID int64, db *gorm.DB) (err error) {
	err = db.Model(&domain.Club{ID: clubID}).Association(domain.ClubFieldLeaders).Delete(user)
	return
}

func InviteUserJoinClubImmediately(inviteID int64, userID int64, clubID int64) (err error) {
	err = services.DBEngine.Transaction(func(tx *gorm.DB) (err error) {
		actor := domain.UserActor{UserID: userID, ClubID: &clubID}
		if err = tx.Save(actor).Error; err != nil {
			return
		}
		result := tx.Model(&domain.ClubInviteLink{ID: inviteID}).Where("invite_count>0").Update("invite_count", "invite_count-1")

		if err = result.Error; err != nil {
			return
		}
		if result.RowsAffected == 0 {
			return errs.ErrInviteLinkIsNullified
		}
		return
	})
	if err != nil {
		return
	}
	return
}

type InviteUserJoinClubMutation struct {
	UserID     int64
	OperatorID int64
	ClubID     int64
}

// InviteUserJoinClub
// 直接邀请某个用户进入社团
// 如果用户从来没有向社团提交过申请则只能由管理员操作
func InviteUserJoinClub(mutation *InviteUserJoinClubMutation) error {
	return InviteUserJoinClubWithTransaction(mutation, services.DBEngine)
}

type FormStatusFlowNode struct {
	Title            string                `json:"title" binding:"required"`
	Description      *string               `json:"description,omitempty"`
	IsDefaultSuccess bool                  `json:"is_default_success,omitempty"`
	IsDefaultFailure bool                  `json:"is_default_failure,omitempty"`
	Children         []*FormStatusFlowNode `json:"children,omitempty"`
}

func (f *FormStatusFlowNode) ToClubFormStatusFlow(clubID int64) *domain.ClubFormStatusFlow {

	children := make([]*domain.ClubFormStatusFlow, 0, len(f.Children))
	for _, child := range f.Children {
		children = append(children, child.ToClubFormStatusFlow(clubID))
	}
	clubFormStatus := &domain.ClubFormStatusFlow{
		ClubID:           &clubID,
		Title:            f.Title,
		Description:      f.Description,
		IsDefaultFailure: f.IsDefaultFailure,
		IsDefaultSuccess: f.IsDefaultSuccess,
		Children:         children,
	}
	return clubFormStatus
}

type UpsertFormStatusFlowMutation struct {
	FlowID   *int64
	UserID   int64
	ClubID   int64
	RootNode *FormStatusFlowNode
}

func UpsertFormStatusFlow(mutation *UpsertFormStatusFlowMutation) (err error) {

	err = services.DBEngine.Transaction(func(db *gorm.DB) (err error) {
		// 删除之前的所有节点
		err = services.DBEngine.Delete(&domain.ClubFormStatusFlow{}, "club_id = ?", mutation.ClubID).Error
		if err != nil {
			return
		}
		// 更新新的节点
		root := mutation.RootNode.ToClubFormStatusFlow(mutation.ClubID)
		err = recursiveSaveFormStatusFlow(root, db)
		if err != nil {
			return
		}
		err = recursiveUpdateFormStatusUpdateID(root, db)
		if err != nil {
			return
		}
		return
	})

	return
}

func recursiveSaveFormStatusFlow(root *domain.ClubFormStatusFlow, db *gorm.DB) (err error) {
	if root == nil {
		return
	}
	err = db.Save(root).Error
	if err != nil {
		return
	}
	for _, child := range root.Children {
		root.Children = append(root.Children, child)
		child.Parent = root
		err = recursiveSaveFormStatusFlow(child, db)
		if err != nil {
			return
		}
	}
	return
}
func recursiveUpdateFormStatusUpdateID(root *domain.ClubFormStatusFlow, db *gorm.DB) (err error) {
	if root == nil {
		return
	}
	if root.Parent != nil {
		root.ParentID = &root.Parent.ID
	}
	err = db.Save(root).Error
	if err != nil {
		return
	}
	for _, child := range root.Children {
		err = recursiveSaveFormStatusFlow(child, db)
	}
	return
}

type ClubFormInfo struct {
	Title        string       `json:"title" form:"title" xml:"title" binding:"required"`
	Description  string       `json:"description,omitempty" form:"description" binding:"-"`
	Value        *domain.JSON `json:"value" form:"value" binding:"required"`
	Type         int64        `json:"type" form:"type" binding:"-"`
	AllowRepeat  bool         `json:"allow_repeat" form:"allow_repeat" xml:"allow_repeat" binding:"-"`
	AllowRewrite bool         `json:"allow_rewrite" form:"allow_rewrite" xml:"allow_rewrite" binding:"-"`
}

type ClubFormInfoUpdate struct {
	Title        *string      `json:"title" form:"title" xml:"title" binding:"-"`
	Description  *string      `json:"description,omitempty" form:"description" binding:"-"`
	Value        *domain.JSON `json:"value" form:"value" binding:"-"`
	Type         *int64       `json:"type" form:"type" binding:"-"`
	AllowRepeat  *bool        `json:"allow_repeat" form:"allow_repeat" xml:"allow_repeat" binding:"-"`
	AllowRewrite *bool        `json:"allow_rewrite" form:"allow_rewrite" xml:"allow_rewrite" binding:"-"`
}

func (c *ClubFormInfoUpdate) ApplyUpdate(form *domain.ClubForm) {
	if c.Type != nil {
		form.Type = *c.Type
	}
	if c.Value != nil {
		form.Value = c.Value
	}
	if c.Title != nil {
		form.Title = *c.Title
	}
	if c.AllowRewrite != nil {
		form.AllowRewrite = *c.AllowRewrite
	}
	if c.AllowRepeat != nil {
		form.AllowRepeat = *c.AllowRepeat
	}
}

func UploadClubForm(clubID int64, info *ClubFormInfo) (form *domain.ClubForm, err error) {
	err = services.DBEngine.Transaction(func(tx *gorm.DB) (err error) {
		form = &domain.ClubForm{
			ClubID:       &clubID,
			Title:        info.Title,
			Description:  info.Description,
			Value:        info.Value,
			Type:         info.Type,
			AllowRepeat:  info.AllowRepeat,
			AllowRewrite: info.AllowRewrite,
		}

		if err = tx.Save(form).Error; err != nil {
			return
		}
		if err = CreateDefaultStatusForForm(form.ID, clubID, tx); err != nil {
			return
		}
		return
	})
	if err != nil {
		return
	}
	return
}
func CreateDefaultStatusForForm(formID, clubID int64, db *gorm.DB) (err error) {
	start := &domain.ClubFormStatusFlow{FormID: &formID, ClubID: &clubID, Title: "等待审核"}

	if err = db.Save(start).Error; err != nil {
		return
	}
	success := &domain.ClubFormStatusFlow{FormID: &formID, ClubID: &clubID, ParentID: &start.ID, Title: "通过", IsDefaultSuccess: true}
	if err = db.Save(success).Error; err != nil {
		return
	}
	failure := &domain.ClubFormStatusFlow{FormID: &formID, ClubID: &clubID, ParentID: &start.ID, IsDefaultFailure: true, Title: "未通过"}
	if err = db.Save(failure).Error; err != nil {
		return
	}
	return
}
func UpdateClubForm(formID int64, info *ClubFormInfoUpdate) (form *domain.ClubForm, err error) {
	form = &domain.ClubForm{ID: formID}
	err = services.DBEngine.Find(form).Error
	if err != nil {
		return
	}
	info.ApplyUpdate(form)
	err = services.DBEngine.Save(form).Error
	if err != nil {
		return
	}
	return
}

type UpdateClubReq struct {
	Name         string  `json:"name" xml:"name" form:"name" binding:"required"`
	FaviconID    *int64  `json:"favicon_id" xml:"favicon_id" form:"favicon_id"`
	PageID       *int64  `json:"page_id" xml:"page_id" form:"page_id"`
	Introduction *string `json:"introduction" xml:"introduction" form:"introduction"`
	Location     *string `json:"location" xml:"location" form:"location"`
	Address      *string `json:"address" xml:"address" form:"address"`
	PrimaryColor string  `json:"primary_color" xml:"primary_color" form:"primary_color"`
}

func UpdateClub(where map[string]interface{}, req UpdateClubReq) (res *domain.Club, err error) {
	db := services.BuildWhere(where, services.DBEngine)
	res = &domain.Club{}
	if err = db.Find(res).Error; err != nil {
		return
	}
	res.Name = req.Name
	res.FaviconID = req.FaviconID
	res.PageID = req.PageID
	res.Introduction = req.Introduction
	res.Location = req.Location
	res.Address = req.Address
	res.PrimaryColor = req.PrimaryColor
	if err = services.DBEngine.Save(res).Error; err != nil {
		return
	}
	return
}

func DeleteClubForm(formID int64) (err error) {
	err = services.DBEngine.Delete(&domain.ClubForm{ID: formID}).Error
	return
}
func DeleteClub(where map[string]interface{}) (err error) {
	db := services.BuildWhere(where, services.DBEngine)
	err = db.Delete(&domain.Club{}).Error
	return
}

func FindClubFormInClub(formID, clubID int64) (res *domain.ClubForm, err error) {
	res = &domain.ClubForm{ID: formID}
	if err = services.DBEngine.Where("club_id=?", clubID).First(res).Error; err != nil {
		return
	}
	return
}

func FindClub(where map[string]interface{}) (res *domain.Club, err error) {
	res = &domain.Club{}
	db := services.BuildWhere(where, services.DBEngine)
	db = db.Joins(domain.ClubFieldPage).Joins(domain.ClubFieldFavicon)
	if err = db.First(res).Error; err != nil {
		return
	}
	return
}

func UpdateApplication(applicationID int64, content map[string]interface{}) (err error) {
	if err = services.DBEngine.Model(&domain.UserApplication{ID: applicationID}).Update("content", domain.JSON(content)).Error; err != nil {
		return
	}
	return
}
